package com.yupi.springbootinit.bizmq;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.rabbitmq.client.Channel;
import com.yupi.springbootinit.exception.ThrowUtils;
import com.yupi.springbootinit.manager.AiManager;
import com.yupi.springbootinit.model.dto.ai.AiChatRequest;
import com.yupi.springbootinit.model.entity.Chart;
import com.yupi.springbootinit.model.enums.TaskStatusEnum;
import com.yupi.springbootinit.service.ChartService;
import com.yupi.springbootinit.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Description
 * @Author minify
 * @Date 2023/12/20 19:43
 * @Project mybi-backend
 */
@Component
@Slf4j
public class MyMessageConsumer {

    @Resource
    private ChartService chartService;

    @RabbitListener(queues = {BiConstant.QUEUE_NAME}, ackMode = "MANUAL")
    public void receiveMessage(String message, Channel channel,
                               @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
        log.info("receiveMessage:接收到消息：{}", message);

        if (StrUtil.isBlank(message)) {
            // 拒绝消息，不用重新放回队列，因为消息为空
            channel.basicNack(deliveryTag, false, false);
            ThrowUtils.throwIf(true, new RuntimeException("消息为空"));
        }

        Long setVoId = Long.parseLong(message);

        try {
            Chart update = new Chart();
            update.setStatus(TaskStatusEnum.RUNNING.getCode());
            update.setExecMessage("图表生成中...");
            update.setId(setVoId);
            boolean result = chartService.updateById(update);
            if (!result) {
                channel.basicNack(deliveryTag, false, false);
                log.error("更新状态失败");
                ThrowUtils.throwIf(true, new RuntimeException("更新状态失败"));
            }
            Chart chart = chartService.getById(setVoId);
            String userInput = buildInput(chart);

            // 请求AI服务接口
            AiChatRequest chatRequest = AiManager.sendAiPost(BiConstant.BI_CODE, userInput);

            String content = chatRequest.getContent();
            String[] genResults = content.split("====");
            String genChart = genResults[1].trim();
            // 加一层校验
            JSONUtil.parse(genChart);
            String genResult = genResults[2].trim();

            Chart finishedUpdate = new Chart();
            finishedUpdate.setId(setVoId);
            finishedUpdate.setStatus(TaskStatusEnum.FINISHED.getCode());
            finishedUpdate.setExecMessage("图表生成完成！");
            finishedUpdate.setGenChart(genChart);
            finishedUpdate.setGenResult(genResult);
            boolean b = chartService.updateById(finishedUpdate);
            if (!b) {
                channel.basicNack(deliveryTag, false, false);
                log.error("更新图表成功状态失败");
                ThrowUtils.throwIf(true, new RuntimeException("更新图表成功状态失败"));
            }
        } catch (Exception e) {
            log.error("生成图表失败", e);
            Chart failedUpdate = new Chart();
            failedUpdate.setId(setVoId);
            failedUpdate.setStatus(TaskStatusEnum.FAILED.getCode());
            failedUpdate.setExecMessage(e.getMessage());
            boolean b = chartService.updateById(failedUpdate);
            if (!b) {
                channel.basicNack(deliveryTag, false, false);
                log.error("更新图表失败状态失败");
                ThrowUtils.throwIf(true, new RuntimeException("更新图表失败状态失败"));
            }
        }

        // 手动确认消息deliveryTag:该消息的index，boolean multiple：是否批量.true:将一次性ack所有小于deliveryTag的消息。
        channel.basicAck(deliveryTag, false);
    }

    private String buildInput(Chart chart) {

        String goal = chart.getGoal();
        String csvData = chart.getChartData();
        // 构造数据输入
        StringBuilder userInput = new StringBuilder();

        // 分析目标
        userInput.append("分析需求：").append("\n");
        userInput.append(goal).append("\n");

        // 压缩数据
        userInput.append("原始数据：").append("\n");
        userInput.append(csvData);
        return userInput.toString();
    }
}
